import signal
import socket
import selectors

sel = selectors.DefaultSelector()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def accept(sock, mask):
    conn, addr = sock.accept()
    print("accepted", conn, ", from", addr)
    conn.setblocking(False)
    sel.register(conn, selectors.EVENT_READ, read)


def read(conn, mask):
    data = conn.recv(1000)
    if data:
        print("echoing", repr(data), "to", conn)
        conn.send(data)
    else:
        print("closing", conn)
        sel.unregister(conn)
        conn.close()

def handler_sigint(signum, frame):
    print("closing server ----")
    sock.close()
    sel.close()

solution="signal"
if solution == "signal":
    # 解决方法1: 接受到信号时, 关闭socket
    signal.signal(signal.SIGINT, handler_sigint)
else:
    # 解决方法2: 快速关闭socket 绑定的addr,port, 立即释放
    # note: address already in use
    # 设置SO_REUSEADDR选项
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # 设置SO_LINGER选项
    linger_option = struct.pack('ii', 1, 0)  # l_onoff=1, l_linger=0
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, linger_option)

sock.bind(("localhost", 6677))
sock.listen(10)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)

while True:
    events = sel.select()
    for key, mask in events:
        callback = key.data
        callback(key.fileobj, mask)
